/******************************************************************************* 
  Copyright (C), 1988-2020, zeno Tech. Co., Ltd.
  Description:   AOUT模块  
  Function List:     
  History:
    <wangmc -- 2014-12-16>  创建
*******************************************************************************/ 

/*=============================================================================
                                 Includes                                  
 =============================================================================*/
#include "audioPriv.h"

/*=============================================================================
                               Macro Definition
 =============================================================================*/


/*=============================================================================
                        Local Structures and Typedef 
 =============================================================================*/


/*=============================================================================
                             Extern Variables                                  
=============================================================================*/


/*=============================================================================
                             Local Variables                                  
 =============================================================================*/


/*=============================================================================
                             Function Definition                                  
 =============================================================================*/

/*******************************************************************************
  Function:     AO_AddRef
  Description:  增加接口引用
  Input:        - pThiz: 音频输出接口指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AO_AddRef(struct AudioOutput *pThiz)
{
    AO_ctl_t *pAoCtl;

    if (!pThiz)
    {
        LOG_PrintError("Output parameter is NULL\n");
        return -1;
    }

    pAoCtl = (AO_ctl_t *)pThiz->priv;
    if (!pAoCtl)
    {
        LOG_PrintError("VideoDecoder isn't initialized\n");
        return -1;
    }
    
    pthread_mutex_lock(&audioCtl_g.aoMutex);

    pAoCtl->refCount++;
    
    pthread_mutex_unlock(&audioCtl_g.aoMutex);
    
    return 0;
}

/*******************************************************************************
  Function:     AO_Release
  Description:  释放接口
  Input:        - pThiz: 音频输出接口指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AO_Release(struct AudioOutput *pThiz)
{
    int ret = 0;
    AO_ctl_t *pAoCtl;

    if (!pThiz)
    {
        LOG_PrintError("Output parameter is NULL\n");
        return -1;
    }

    pAoCtl = (AO_ctl_t *)pThiz->priv;
    if (!pAoCtl)
    {
        LOG_PrintError("VideoDecoder isn't initialized\n");
        return -1;
    }
    
    pthread_mutex_lock(&audioCtl_g.aoMutex);

    if (pAoCtl->refCount > 1)
    {
        pAoCtl->refCount--;
        goto unlock_mutex;
    }

    pAoCtl->refCount--;

    audioCtl_g.pAoCtls[pAoCtl->aoChn] = NULL;
    free(pAoCtl);    
    
unlock_mutex:       
    pthread_mutex_unlock(&audioCtl_g.aoMutex);
    return ret;
}

/*******************************************************************************
  Function:     AO_GetCaps
  Description:  得到音频输出支持的特性。
  Input:        - pThiz: 音频输出接口指针
  Output:       - pCaps: 指向音频输出特性结构AudioOutCaps的指针。
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AO_GetCaps(struct AudioOutput *pThiz, AudioOutCaps *pCaps)
{
	pCaps->mixing		= 0;

	return 0;
}

/*******************************************************************************
  Function:     AO_OutPut
  Description:  将音频源合成到音频输出。如果输出设备支持混音，
                则可以将多路源同时输出;否则需要根据具体业务，
                先禁止输出优先级低的音频源,仅输出优先级最高的音频源。
  Input:        - pThiz: 音频输出接口指针
                - pSource: 音频源指针
                - enable: 0-禁止该源，1-输出该源。
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AO_OutPut(struct AudioOutput *pThiz, AudioSource *pSource, int enable)
{
	return 0;
}

/*******************************************************************************
  Function:     AO_SetVolume
  Description:  设置音频输出的音量
  Input:        - pThiz: 音频输出接口指针
                - volume: 音量，取值0-100，0表示静音
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AO_SetVolume(struct AudioOutput *pThiz, int volume)
{
	return 0;
}

/*******************************************************************************
  Function:     getAudioOutputChannels
  Description:  得到音频输出通道的个数
  Input:        无
  Output:       无
  Return:       音频输出通道个数
  Others:       无
*******************************************************************************/
int PAL_API getAudioOutputChannels(void)
{
	return audioCtl_g.logicChnOutNum;
}


/*******************************************************************************
  Function:     AO_SetAudioInAttr
  Description:  设置AudioIn通道属性
  Input:        - pThiz: 音频输入接口指针
                - aoAttr：通道属性
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AO_SetAudioInAttr(struct AudioOutput *pThiz, AudioOutAttr aoAttr)
{
    int ret = 0;
    AO_ctl_t *pAoCtl;

    if (!pThiz)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    pAoCtl = (AO_ctl_t *)pThiz->priv;
    if (!pAoCtl)
    {
        LOG_PrintError("pAoCtl is NULL\n");
        return -1;
    }

    if( pAoCtl->aoChnState == AI_STREAM_START)
    {
		LOG_PrintWarn("AO chn %d have been start!\n", pAoCtl->aoChn);
		return -1;
	}
    
    pthread_mutex_lock(&audioCtl_g.aoMutex);

    AO_CHN_ATTR_S* aoChnAttr = &pAoCtl->aoChnAttr;

    printf("aoAttr.pcAudioNode=%s, u32Channels=%d, u32SampleRate=%d, u32NbSamples=%d\n",
        aoAttr.pcAudioNode, aoAttr.u32Channels, aoAttr.u32SampleRate ,aoAttr.u32NbSamples);

    strcpy(pAoCtl->aoChnAttr.pcAudioNode, aoAttr.pcAudioNode);   
    aoChnAttr->enSampleFormat = aoAttr.enSampleFormat;
    aoChnAttr->u32Channels = aoAttr.u32Channels;
    aoChnAttr->u32SampleRate = aoAttr.u32SampleRate;
    aoChnAttr->u32NbSamples = aoAttr.u32NbSamples;

     
    pthread_mutex_unlock(&audioCtl_g.aoMutex);   
    
    return ret;
}

/*******************************************************************************
  Function:     AO_Start
  Description:  启动AudioIn通道
  Input:        - pThiz: 音频输入接口指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AO_Start(struct AudioOutput *pThiz)
{
    int ret = 0;
    int result = 0;
    AO_ctl_t *pAoCtl;

    if (!pThiz)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    pAoCtl = (AO_ctl_t *)pThiz->priv;
    if (!pAoCtl)
    {
        LOG_PrintError("pAoCtl is NULL\n");
        return -1;
    }
    
    pthread_mutex_lock(&audioCtl_g.aoMutex);

    if(pAoCtl->aoChnState == AO_STREAM_START)
    {
		LOG_PrintWarn("AO chn %d have been start!\n", pAoCtl->aoChn);
		goto mutex_unlock;
	}

    ret = RK_MPI_AO_SetChnAttr(pAoCtl->aoChn, &pAoCtl->aoChnAttr);
    if (ret)
    {
        LOG_PrintError("AO etChnAttr err:%d\n", ret);
        goto mutex_unlock;
    }

    ret = RK_MPI_AO_EnableChn(pAoCtl->aoChn);
    if (ret)
    {
        LOG_PrintError("AO enable err:%d\n", ret);
        goto mutex_unlock;
    }

    pAoCtl->aoChnState = AO_STREAM_START;

    LOG_PrintInfo("AO_Start aoChn:%d success\n",pAoCtl->aoChn);

mutex_unlock:
    pthread_mutex_unlock(&audioCtl_g.aoMutex);
    
    return ret;
}

/*******************************************************************************
  Function:     AO_Stop
  Description:  停止AudioIn通道
  Input:        - pThiz: 音频输入接口指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AO_Stop(struct AudioOutput *pThiz)
{
    int ret = 0;
    int result = 0;
    AO_ctl_t *pAoCtl;

    if (!pThiz)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    pAoCtl = (AO_ctl_t *)pThiz->priv;
    if (!pAoCtl)
    {
        LOG_PrintError("pAoCtl is NULL\n");
        return -1;
    }
    
    pthread_mutex_lock(&audioCtl_g.aoMutex);
    
    if(pAoCtl->aoChnState == AO_STREAM_STOP)
    {
		LOG_PrintWarn("AO chn %d have been stop!\n", pAoCtl->aoChn);
		goto mutex_unlock;
	}

	ret = RK_MPI_AO_DisableChn(pAoCtl->aoChn);
    if (ret)
    {
        LOG_PrintError("AO enable err:%d\n", ret);
        goto mutex_unlock;
    }

    pAoCtl->aoChnState = AO_STREAM_STOP;

    LOG_PrintInfo("AO_Stop aoChn:%d success\n",pAoCtl->aoChn);

mutex_unlock:
    pthread_mutex_unlock(&audioCtl_g.aoMutex);
    
    return ret;
}

static int AO_SendData(struct AudioOutput *pThiz, char *pData, int len)
{
    AO_ctl_t *pAoCtl = NULL;
    if (!pThiz)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    pAoCtl = (AO_ctl_t *)pThiz->priv;
    if (!pAoCtl)
    {
        LOG_PrintError("pAoCtl is NULL\n");
        return -1;
    }

    if(pAoCtl->aoChnState == AO_STREAM_STOP)
    {
        LOG_PrintError("AudioOutput aoChnState is stop\n");
        return -1;
    }
    
    MEDIA_BUFFER pstLineOutData = NULL;
    int ret = 0;
    int u32ReadSize = len;
    pstLineOutData = RK_MPI_MB_CreateAudioBuffer(u32ReadSize, RK_FALSE);
    if (!pstLineOutData) {
        LOG_PrintError("ERROR: create audio buffer\n");
        return -1;
    }
    
    memcpy(RK_MPI_MB_GetPtr(pstLineOutData), pData, u32ReadSize);
    RK_MPI_MB_SetSize(pstLineOutData, u32ReadSize);
    ret = RK_MPI_SYS_SendMediaBuffer(RK_ID_AO, pAoCtl->aoChn, pstLineOutData);
    if (ret) {
        LOG_PrintError("ERROR: RK_MPI_SYS_SendMediaBuffer failed! ret = %d\n", ret);
        ret = -1;
        goto release_buffer;
    }

#if 0
    uint64 pts = vdo_get_time();
    LOG_PrintWarn("RK_MPI_SYS_SendMediaBuffer RK_ID_AO len=%d,PTS=%llu\n", u32ReadSize, pts);
    //HexPrint("audio", pAudioEncPacket->buffer + AENC_FRAME_LEN, 64);
    //FILE_write("/root/lineout.pcm", pAudioEncPacket->buffer + AENC_FRAME_LEN, AENC_FRAME_LEN);
#endif    
release_buffer:
    ret = RK_MPI_MB_ReleaseBuffer(pstLineOutData);
    if (ret)
    {
        LOG_PrintError("RK_MPI_MB_ReleaseBuffer fail chn %d ret 0x%x\n\n",pAoCtl->aoChn, ret);
        ret = -1;
    }
    pstLineOutData = NULL;    
    return ret;
}

/*******************************************************************************
  Function:     createAudioOutput
  Description:  创建音频输出接口
  Input:        - pDesc: 音频输出接口描述结构AudioOutDesc指针
  Output:       - ppAudioOutput:  音频输出接口指针的指针
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
int PAL_API createAudioOutput(AudioOutDesc *pDesc, AudioOutput **ppAudioOutput)
{
    int ret = 0;
    AudioOutput *pAudioOutput;
    AO_ctl_t *pAoCtl;
    unsigned int channel = 0;

    if ((NULL == pDesc) || (NULL == ppAudioOutput))
    {
        LOG_PrintError("Parameter is NULL!\n");
        return -1;
    }

    channel = pDesc->channel;

    if (channel >= AUDIO_LOGICOUT_MAX || channel < 0)
    {
        LOG_PrintError("Audio output Channel (%d) is out of range!\n", 
                       channel);
        return -1;
    }

    pthread_mutex_lock(&audioCtl_g.aoMutex);
    
    pAoCtl = audioCtl_g.pAoCtls[channel];
    if (pAoCtl)
    {
        LOG_PrintInfo("audio output has already been created\n");
        pAoCtl->refCount++;
        *ppAudioOutput = &pAoCtl->audioOutput;
        goto mutex_unlock;
    }

    pAoCtl = (AO_ctl_t *)malloc(sizeof(AO_ctl_t));
    if (!pAoCtl)
    {
        LOG_PrintError("There is no enough memory to allocate!\n");
        ret = -1;
        goto mutex_unlock;
    }
    memset(pAoCtl, 0, sizeof(AO_ctl_t));
    
    pAoCtl->refCount++;
    pAoCtl->aoChn = channel;
    pAoCtl->aoChnAttr.pcAudioNode = (RK_CHAR *)malloc(32 * sizeof(RK_CHAR));
    pAoCtl->aoChnState = AO_STREAM_STOP;

    audioCtl_g.pAoCtls[channel] = pAoCtl;

    pAudioOutput                             = &pAoCtl->audioOutput;
    pAudioOutput->priv                       = pAoCtl;
    pAudioOutput->addRef                     = AO_AddRef;
    pAudioOutput->release                    = AO_Release;
    pAudioOutput->getCaps                    = AO_GetCaps;
    pAudioOutput->output                     = AO_OutPut;
    pAudioOutput->setVolume                  = AO_SetVolume;
    pAudioOutput->start                      = AO_Start;
    pAudioOutput->stop                       = AO_Stop;
    pAudioOutput->setChnAttr                 = AO_SetAudioInAttr;
    pAudioOutput->sendDataToAo               = AO_SendData;
    
    *ppAudioOutput = &pAoCtl->audioOutput;
    
    LOG_PrintInfo("Create aoChn:%d successfully!\n", pAoCtl->aoChn);
    goto mutex_unlock;
        
mutex_unlock:
    pthread_mutex_unlock(&audioCtl_g.aoMutex);
    return ret;
}
